package com.novunda.platform.web;

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.novunda.platform.common.exception.NovException;
import com.novunda.platform.common.exception.ValidationErrorException;
import com.novunda.platform.common.utils.CheckNameUtil;
import com.novunda.platform.common.utils.PinYinUtil;
import com.novunda.platform.common.utils.UserUtils;
import com.novunda.platform.common.web.controller.BaseController;
import com.novunda.platform.entities.Office;
import com.novunda.platform.entities.Role;
import com.novunda.platform.entities.User;
import com.novunda.platform.services.OfficeService;
import com.novunda.platform.web.model.ResultModel;

import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

/**
 * . 功能说明：机构controller
 *
 * @author linfeng
 * @version 1.0
 * @modify FJ
 * @since 2016/9/5
 */
@Controller
@RequestMapping(value = "/sys/office")
public class OfficeController extends BaseController {

	/**
	 * . 机构列表url
	 */
	private final String OFFICE_URL = "redirect:/sys/office/";

	/**
	 * . 机构service
	 */
	@Autowired
	private OfficeService officeService;

	/**
	 * . 功能说明：根据id查询机构
	 *
	 * @param id
	 *            机构id
	 * @return
	 */
	@ModelAttribute("office")
	public Office get(@RequestParam(required = false) Long id) {
		// 如果id为空
		if (id != null) {
			return officeService.get(id);
		} else {
			return new Office();
		}
	}

	/**
	 * . 功能说明：机构列表查询
	 *
	 * @param office
	 * @param model
	 * @return
	 */
	@RequiresPermissions("sys:office:view")
	@RequestMapping({ "list", "" })
	public String list(Office office, Model model) {
		User user = UserUtils.getUser();
		// 如果当前登录用户为admin
		if (user.isAdmin()) {
			office.setId(1L);
		} else {
			office.setId(user.getOffice().getId());
			// 如果登录用户所含角色中有角色范围为查看所有的时候
			List<Role> list = user.getRoleList();
			for (Role role : list) {
				if (role.getDataScope().equals(Role.DATA_SCOPE_ALL)) {
					office.setId(1L);
				}
			}
		}
		model.addAttribute("office", office);
		List<Office> list = Lists.newArrayList();
		List<Office> sourcelist = officeService.findAll();
		Office.sortList(list, sourcelist, office.getId());
		model.addAttribute("list", list);
		return "modules/sys/officeTree";
	}

	/**
	 * . 功能说明：添加机构页面跳转
	 *
	 * @param office
	 *            机构对象
	 * @param model
	 * @return
	 */
	@RequiresPermissions("sys:office:view")
	@RequestMapping(value = "form", headers = "X-Requested-With=XMLHttpRequest")
	public String form(Office office, Model model) {
		User user = UserUtils.getUser();
		// 如果没有父机构
		if (office.getParent() == null || office.getParent().getId() == null) {
			// 如果当前登录人是admin
			if (user.isAdmin()) {
				office.setParent(officeService.get(1l));
			} else {
				office.setParent(user.getCompany());
			}
		} else {
			office.setParent(officeService.get(office.getParent().getId()));
		}
		model.addAttribute("office", office);
		model.addAttribute("user", user);
		return "modules/sys/officeForm";
	}

	/**
	 * . 功能说明：保存机构
	 *
	 * @param office
	 *            机构实体对象
	 * @param model
	 * @param redirectAttributes
	 * @return
	 */
	@RequiresPermissions(value = {"sys:office:edit","sys:office:add"},logical=Logical.OR)
	@RequestMapping(value = "save", method = RequestMethod.POST)
	public String save(Office office, Model model, RedirectAttributes redirectAttributes) {
		try {
			// 服务端参数有效性验证
			if (!beanValidator(model, office)) {
				return form(office, model);
			}

			Long orgId = office.getId();
			// 如果id为空则为添加，验证机构名
			if (null == orgId) {
				// 如果父机构的类型为部门则不允许再创建任何组织
				Office parent = office.getParent();
				if (null != parent) {
					parent = officeService.get(parent.getId());
					if (parent != null && parent.getType().equals("2")) {
						throw new ValidationErrorException("部门下不允许再创建部门或者机构");
					}
				}
				String orgName = office.getName();
				CheckNameUtil.checkNameIsNull("机构名", orgName);
				CheckNameUtil.checkOrgNamePattern(orgName);
				// 如果添加类型为机构，验证机构名和设置机构编码
				String type = office.getType();
				if (type.equals("1")) {
					if (officeService.getOfficeByName(orgName) != null) {
						throw new ValidationErrorException("机构名已存在");
					}
					// 如果添加类型为公司，设置机构编码
					if (type.equals("1")) {
						office.setCode(PinYinUtil.getFirstSpell(orgName));
					}
				} else {
					// 如果类型为部门
					if (officeService.getOfficeByNameAndTypeAndParent(orgName, office.getParent().getId()) != null) {
						throw new ValidationErrorException("部门名已存在");
					}
				}
			}

			officeService.save(office);
			addMessage(redirectAttributes, "保存机构'" + office.getName() + "'成功");
		} catch (ValidationErrorException e) {
			addMessage(model, "保存" + (office.getType().equals("1") ? "机构：" : "部门：") + office.getName() + "失败，" + e.getMessage());
			model.addAttribute("returnMessage", "save_office_error");
			return form(office, model);
		} catch (BadHanyuPinyinOutputFormatCombination e) {
			LOG.error(e.getMessage(), e);
			addMessage(model, "保存" + (office.getType().equals("1") ? "机构" : "部门") + "失败，异常：" + e.getMessage());
			model.addAttribute("returnMessage", "save_office_error");
			return form(office, model);
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
			addMessage(model, "保存" + (office.getType().equals("1") ? "机构" : "部门") + "失败，异常：" + e.getMessage());
			model.addAttribute("returnMessage", "save_office_error");
			return form(office, model);
		}
        model.addAttribute("returnMessage", "save_office_ok");
		return OFFICE_URL;
	}

	/**
	 * . 功能说明：删除机构
	 *
	 * @param id
	 *            机构id
	 * @param redirectAttributes
	 * @return
	 */
	@RequiresPermissions("sys:office:delete")
	@RequestMapping("delete")
	public String delete(Long id, RedirectAttributes redirectAttributes) {

		// 如果是根机构
		if (Office.isRoot(id)) {
			addMessage(redirectAttributes, "删除机构失败, 不允许删除顶级机构或编号空");
			return OFFICE_URL;
		}

		Office office = officeService.get(id);
		List<Office> childOffices = office.getChildList();
		List<User> users = office.getUserList();
		List<Role> roles = office.getRoleList();
		// 如果存在子机构、角色或用户
		if ((null != childOffices && !childOffices.isEmpty()) || (null != users && !users.isEmpty())
				|| (null != roles && !roles.isEmpty())) {
			String info = "删除" + (office.getType().equals("1") ? "机构" : "部门") + "失败,存在";
			if (office.getType().equals("1")) {
				info += "子机构、角色或";
			}
			addMessage(redirectAttributes, info + "用户");
			return OFFICE_URL;
		}

		officeService.delete(id);
		addMessage(redirectAttributes, "删除" + (office.getType().equals("1") ? "机构" : "部门") + "成功");
		return OFFICE_URL;
	}

	/**
	 * . 功能说明：ajax查询机构树结构
	 *
	 * @param extId
	 *            指定存在的机构id
	 * @param type
	 *            机构类型
	 * @param response
	 * @return
	 */
	@RequiresUser
	@ResponseBody
	@RequestMapping(value = "treeDataOffice", produces = "application/json; charset=UTF-8")
	public List<Map<String, Object>> treeDataOffice(@RequestParam(required = false) Long extId,
			@RequestParam(required = false) Long type, HttpServletResponse response) {

		response.setContentType("application/json; charset=UTF-8");
		List<Map<String, Object>> mapList = Lists.newArrayList();
		List<Office> list = officeService.findAll();
		for (Office e : list) {
			if ((extId == null || !extId.equals(e.getId()) && !e.getParentIds().contains("," + extId + ","))
					&& (type == null || Integer.parseInt(e.getType()) <= type.intValue())) {
				Map<String, Object> map = Maps.newHashMap();
				map.put("id", e.getId());
				map.put("pId", e.getParent() != null ? e.getParent().getId() : 0);
				map.put("name", e.getName());
				if ("1".equals(e.getType())) {
					map.put("iconSkin", "company");
				}
				map.put("type", e.getType());
				// map.put("iconSkin", "1".equals(e.getType()) ? "company":
				// "office");
				mapList.add(map);
			}
		}

		return mapList;

	}

	/**
	 * . 功能说明：ajax查询机构树结构，不包含根机构
	 *
	 * @param extId
	 *            指定存在的机构id
	 * @param type
	 *            机构类型
	 * @param response
	 * @return
	 */
	@RequiresUser
	@ResponseBody
	@RequestMapping(value = "treeData", produces = "application/json; charset=UTF-8")
	public List<Map<String, Object>> treeData(@RequestParam(required = false) Long extId,
			@RequestParam(required = false) Long type, HttpServletResponse response) {
		response.setContentType("application/json; charset=UTF-8");
		List<Map<String, Object>> mapList = Lists.newArrayList();
		User currentUser = UserUtils.getUser();
		// 如果是admin，查看所有
		if (currentUser.isAdmin()) {
			extId = null;
		}
		List<Office> list = officeService.findAll();
		for (Office e : list) {
			if ((extId == null || extId.equals(e.getId()) && !e.getParentIds().contains("," + extId + ","))
					&& (type == null || Integer.parseInt(e.getType()) == type.intValue()) && e.getId() != 1) {
				Map<String, Object> map = Maps.newHashMap();
				map.put("id", e.getId());
				map.put("pId", e.getParent() != null ? e.getParent().getId() : 0);
				map.put("name", e.getName());
				mapList.add(map);
			}
		}

		return mapList;

	}

	/**
	 * . 功能说明：ajax查询父机构等于所属机构的部门
	 *
	 * @param extId
	 *            指定存在的机构id
	 * @param type
	 *            机构类型
	 * @param response
	 * @return
	 */
	@RequiresUser
	@ResponseBody
	@RequestMapping(value = "treeDataChild", produces = "application/json; charset=UTF-8")
	public List<Map<String, Object>> treeDataChild(@RequestParam(required = false) Long extId,
			@RequestParam(required = false) Long type, HttpServletResponse response) {

		response.setContentType("application/json; charset=UTF-8");
		List<Map<String, Object>> mapList = Lists.newArrayList();
		List<Office> list = officeService.findAll();
		for (Office e : list) {
			if (null != e.getParent() && e.getParent().getId().equals(extId) && e.getType().equals("2")) {
				Map<String, Object> map = Maps.newHashMap();
				map.put("id", e.getId());
				map.put("pId", e.getParent() != null ? e.getParent().getId() : 0);
				map.put("name", e.getName());
				mapList.add(map);
			}
		}

		return mapList;

	}

	/**
	 * . 功能说明：检查机构名
	 *
	 * @param name
	 *            机构名
	 * @return
	 */
	@ResponseBody
	// @RequiresPermissions("sys:user:edit")
	@RequestMapping("checkName")
	public String checkName(String name) {
		try {
			CheckNameUtil.checkNameIsNull("机构名", name);
			CheckNameUtil.checkOrgNamePattern(name);
		} catch (ValidationErrorException e) {
			return "false";
		}
		return "true";
	}

	/**
	 * 开发者创建应用时新增机构
	 *
	 * @param orgName
	 *            机构名称
	 * @return 操作结果
	 */
	@ResponseBody
	@RequestMapping(value = "add", produces = "application/json;charset=utf-8")
	public ResultModel<Office> add(String orgName) {
		ResultModel<Office> resultModel = new ResultModel<Office>();
		try {
			CheckNameUtil.checkNameIsNull("机构名", orgName);
			CheckNameUtil.checkOrgNamePattern(orgName);
			Office office = officeService.getOfficeByName(orgName);
			if (null == office) {
				office = new Office();
				office.setParent(officeService.get(1l));
				office.setParentIds("0,1,");
				office.setType("1");
				office.setName(orgName);
				office.setCode(PinYinUtil.getFirstSpell(orgName));
				office = officeService.justSave(office);
			}
			resultModel.setObject(office);
		} catch (ValidationErrorException e) {
			resultModel.setReturnCode(1);
			resultModel.setReturnMessage(e.getMessage());
		} catch (BadHanyuPinyinOutputFormatCombination e) {
			LOG.error(e.getMessage(), e);
			resultModel.setReturnCode(2);
			resultModel.setReturnMessage("orgName to pinyin exception : " + e.getMessage());
		} catch (NovException e) {
			LOG.error(e.getMessage(), e);
			resultModel.setReturnCode(-1);
			resultModel.setReturnMessage("inner exception : " + e.getMessage());
		}
		return resultModel;

	}

	@RequiresUser
	@ResponseBody
	@RequestMapping(value = "rootTreeData", produces = "application/json; charset=UTF-8")
	public List<Map<String, Object>> rootTreeData(@RequestParam(required = false) Long extId,
			@RequestParam(required = false) Long type, HttpServletResponse response) {

		response.setContentType("application/json; charset=UTF-8");
		List<Map<String, Object>> mapList = Lists.newArrayList();

		Office office = officeService.get(1L);
		mapList.add(childOffice(office, extId, type));

		return mapList;

	}

	private Map<String, Object> childOffice(Office office, Long extId, Long type) {

		Map<String, Object> map = Maps.newHashMap();
		if ((extId == null || !extId.equals(office.getId()) && !office.getParentIds().contains("," + extId + ","))
				&& (type == null || Integer.parseInt(office.getType()) <= type.intValue())) {

			if (office.getId() == 1L) {
				map.put("name", office.getName() + "<div class=\"tree-actions\"><i class=\"fa fa-plus\" data-id=\""
						+ office.getId() + "\"></i></div>");
			} else {
				map.put("name",
						office.getName() + "<div class=\"tree-actions\"><i class=\"fa fa-plus\" data-id=\""
								+ office.getId() + "\"></i><i class=\"fa fa-edit\" data-id=\"" + office.getId()
								+ "\"></i><i class=\"fa fa-trash-o\" data-id=\"" + office.getId() + "\"></i></div>");
			}

			// 公司
			if ("1".equals(office.getType())) {
				map.put("type", "folder");
			}
			// 部门
			else {
				map.put("type", "item");
			}

			Map<String, Object> additionalParametersMap = Maps.newHashMap();

			map.put("additionalParameters", additionalParametersMap);

			additionalParametersMap.put("id", office.getId());

			if (!office.getChildList().isEmpty()) {

				List<Map<String, Object>> mapList = Lists.newArrayList();
				for (Office childOffice : office.getChildList()) {
					mapList.add(childOffice(childOffice, extId, type));
				}
				additionalParametersMap.put("children", mapList);

			}

		}

		return map;

	}

}
